package space

import (
	"src/zeus/entity"
	"src/zeus/iserver"
	"src/zeus/linmath"
	"src/zeus/logger"
	"src/zeus/msgdef"
	"src/zeus/serializer"
)

type delayedCastMsg struct {
	//发出去的消息
	msg msgdef.IMsg
	// 发出去的二进制数据
	buff []byte
	//是否发给自己
	isCastToMe bool
	//是否发给周围的人
	isCastOther bool
}

/*
	往期教训：在检查广播接口顺序时要注意调用者的一致性。
			 调用实体的不同可能会影响客户端收到的顺序。

*/

// CastMsgToAllClient 发送消息给所有关注我的客户端
func (e *Entity) CastMsgToAllClient(msg msgdef.IMsg) {
	buf, err := entity.PackRaw(msg)
	if err != nil {
		logger.Errorf("CastMsgToAllClient:%s", err)
		return
	}
	if e.GetSpace().EntityCount() <= 1 {
		//只有自己
		e.delayedCastMsgs = append(e.delayedCastMsgs, &delayedCastMsg{
			// msg:         msg,
			isCastToMe:  true,
			isCastOther: false,
			buff:        buf,
		})
	} else {
		li := make(map[uint64][]uint64)
		e.GetSpace().TravsalAOI(e, func(ia iserver.ICoordEntity) bool {
			if ise, ok := ia.(iserver.IEntityStateGetter); ok {
				if ise.GetEntityState() != iserver.Entity_State_Loop {
					return false
				}
				if !ia.ExistsAOIWeather(e) {
					return false
				}
				if ie, ok := ia.(iserver.IEntity); ok && ia.GetID() != e.GetID() {
					sid, _, _ := ie.GetEntitySrvID(iserver.ServerTypeClient)
					li[sid] = append(li[sid], ie.GetID())
				}
				// if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
				// 	ie.CastMsgToMeRaw(buf)
				// 	// ie.CastMsgToMe(msg)
				// 	// ie.Post(iserver.ServerTypeClient, msg)
				// }
			}
			return false
		})
		//自己部分
		sid, _, _ := e.GetEntitySrvID(iserver.ServerTypeClient)
		li[sid] = append(li[sid], e.GetID())
		for sid, eids := range li {
			e.GetSpace().BroadCastMsgRaw(sid, iserver.ServerTypeClient, 0,
				buf, eids...)
		}
	}
}

// CastMsgToMe 发送消息给自己
func (e *Entity) CastMsgToMe(msg msgdef.IMsg) {
	e.delayedCastMsgs = append(e.delayedCastMsgs, &delayedCastMsg{
		msg:         msg,
		isCastToMe:  true,
		isCastOther: false,
	})
	// e.Post(iserver.ServerTypeClient, msg)
}

// 是帧尾给自己发消息
func (e *Entity) CastMsgToMeRaw(buff []byte) {
	e.delayedCastMsgs = append(e.delayedCastMsgs, &delayedCastMsg{
		isCastToMe:  true,
		isCastOther: false,
		buff:        buff,
	})
}

// CastMsgToAllClientExceptMe  发送给除了自己外的其它人
func (e *Entity) CastMsgToAllClientExceptMe(msg msgdef.IMsg) {
	buf, err := entity.PackRaw(msg)
	if err != nil {
		logger.Errorf("CastMsgToAllClient:%s", err)
		return
	}
	if e.GetSpace().EntityCount() <= 1 {
		//只有自己，如果除自己那就没人了

	} else {
		li := make(map[uint64][]uint64)
		e.GetSpace().TravsalAOI(e, func(ia iserver.ICoordEntity) bool {
			if ise, ok := ia.(iserver.IEntityStateGetter); ok {
				if ise.GetEntityState() != iserver.Entity_State_Loop {
					return false
				}
				if !ia.ExistsAOIWeather(e) {
					return false
				}
				if ie, ok := ia.(iserver.IEntity); ok && ia.GetID() != e.GetID() {
					sid, _, _ := ie.GetEntitySrvID(iserver.ServerTypeClient)
					li[sid] = append(li[sid], ie.GetID())
				}
				// if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
				// 	ie.CastMsgToMeRaw(buf)
				// 	// ie.CastMsgToMe(msg)
				// 	// ie.Post(iserver.ServerTypeClient, msg)
				// }
			}
			return false
		})
		for sid, eids := range li {
			e.GetSpace().BroadCastMsgRaw(sid, iserver.ServerTypeClient, 0,
				buf, eids...)
		}
	}
}

func (e *Entity) CastMsgToRangeExceptMe(center *linmath.Vector3, radius int, msg msgdef.IMsg) {
	buf, err := entity.PackRaw(msg)
	if err != nil {
		logger.Errorf("CastMsgToAllClient:%s", err)
		return
	}
	if e.GetSpace().EntityCount() <= 1 {
		//因为地图上只有自己，除了自己就没人了
		// e.delayedCastMsgs = append(e.delayedCastMsgs, &delayedCastMsg{
		// 	// msg:         msg,
		// 	isCastToMe:  true,
		// 	isCastOther: false,
		// 	buff:        buf,
		// })
	} else {
		li := make(map[uint64][]uint64)
		e.GetSpace().TravsalRange(center, radius, func(ia iserver.ICoordEntity) bool {
			if ise, ok := ia.(iserver.IEntityStateGetter); ok {
				if ise.GetEntityState() != iserver.Entity_State_Loop {
					return false
				}
				if !ia.ExistsAOIWeather(e) {
					return false
				}
				if ie, ok := ia.(iserver.IEntity); ok && ia.GetID() != e.GetID() {
					sid, _, _ := ie.GetEntitySrvID(iserver.ServerTypeClient)
					li[sid] = append(li[sid], ie.GetID())
				}
				// if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
				// 	ie.CastMsgToMeRaw(buf)
				// 	// ie.CastMsgToMe(msg)
				// 	// ie.Post(iserver.ServerTypeClient, msg)
				// }
			}
			return false
		})

		for sid, eids := range li {
			e.GetSpace().BroadCastMsgRaw(sid, iserver.ServerTypeClient, 0,
				buf, eids...)
		}

	}
}

func (e *Entity) CastMsgToRange(center *linmath.Vector3, radius int, msg msgdef.IMsg) {
	buf, err := entity.PackRaw(msg)
	if err != nil {
		logger.Errorf("CastMsgToAllClient:%s", err)
		return
	}
	if e.GetSpace().EntityCount() <= 1 {
		e.delayedCastMsgs = append(e.delayedCastMsgs, &delayedCastMsg{
			// msg:         msg,
			isCastToMe:  true,
			isCastOther: false,
			buff:        buf,
		})
		// e.GetSpace().TravsalRange(center, radius, func(ia iserver.ICoordEntity) bool {
		// 	if ise, ok := ia.(iserver.IEntityStateGetter); ok {
		// 		if ise.GetEntityState() != iserver.Entity_State_Loop {
		// 			return false
		// 		}
		// 		if !ia.ExistsAOIWeather(e) {
		// 			return false
		// 		}
		// 		if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
		// 			ie.CastMsgToMeRaw(buf)
		// 			// ie.CastMsgToMe(msg)
		// 			// ie.Post(iserver.ServerTypeClient, msg)
		// 		}
		// 	}
		// 	return false
		// })
	} else {
		li := make(map[uint64][]uint64)
		e.GetSpace().TravsalRange(center, radius, func(ia iserver.ICoordEntity) bool {
			if ise, ok := ia.(iserver.IEntityStateGetter); ok {
				if ise.GetEntityState() != iserver.Entity_State_Loop {
					return false
				}
				if !ia.ExistsAOIWeather(e) {
					return false
				}
				if ie, ok := ia.(iserver.IEntity); ok {
					sid, _, _ := ie.GetEntitySrvID(iserver.ServerTypeClient)
					li[sid] = append(li[sid], ie.GetID())
				}
				// if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
				// 	ie.CastMsgToMeRaw(buf)
				// 	// ie.CastMsgToMe(msg)
				// 	// ie.Post(iserver.ServerTypeClient, msg)
				// }
			}
			return false
		})
		// //自己部分
		// sid, _, _ := e.GetEntitySrvID(iserver.ServerTypeClient)
		// li[sid] = append(li[sid], e.GetID())
		for sid, eids := range li {
			e.GetSpace().BroadCastMsgRaw(sid, iserver.ServerTypeClient, 0,
				buf, eids...)
		}
	}
}

func (e *Entity) CastMsgToCenterExceptMe(center *linmath.Vector3, radius int, msg msgdef.IMsg) {
	buf, err := entity.PackRaw(msg)
	if err != nil {
		logger.Errorf("CastMsgToAllClient:%s", err)
		return
	}
	if e.GetSpace().EntityCount() <= 1 {
		e.GetSpace().TravsalCenter(center, radius, func(ia iserver.ICoordEntity) bool {
			if ise, ok := ia.(iserver.IEntityStateGetter); ok {
				if ise.GetEntityState() != iserver.Entity_State_Loop {
					return false
				}
				if !ia.ExistsAOIWeather(e) {
					return false
				}
				if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
					ie.CastMsgToMeRaw(buf)
					// ie.CastMsgToMe(msg)
					// ie.Post(iserver.ServerTypeClient, msg)
				}
			}
			return false
		})
	} else {
		li := make(map[uint64][]uint64)
		e.GetSpace().TravsalCenter(center, radius, func(ia iserver.ICoordEntity) bool {
			if ise, ok := ia.(iserver.IEntityStateGetter); ok {
				if ise.GetEntityState() != iserver.Entity_State_Loop {
					return false
				}
				if !ia.ExistsAOIWeather(e) {
					return false
				}
				if ie, ok := ia.(iserver.IEntity); ok && ia.GetID() != e.GetID() {
					sid, _, _ := ie.GetEntitySrvID(iserver.ServerTypeClient)
					li[sid] = append(li[sid], ie.GetID())
				}
				// if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
				// 	ie.CastMsgToMeRaw(buf)
				// 	// ie.CastMsgToMe(msg)
				// 	// ie.Post(iserver.ServerTypeClient, msg)
				// }
			}
			return false
		})
		for sid, eids := range li {
			e.GetSpace().BroadCastMsgRaw(sid, iserver.ServerTypeClient, 0,
				buf, eids...)
		}
	}

}

func (e *Entity) CastMsgToCenter(center *linmath.Vector3, radius int, msg msgdef.IMsg) {
	buf, err := entity.PackRaw(msg)
	if err != nil {
		logger.Errorf("CastMsgToAllClient:%s", err)
		return
	}
	if e.GetSpace().EntityCount() <= 1 {
		e.delayedCastMsgs = append(e.delayedCastMsgs, &delayedCastMsg{
			// msg:         msg,
			isCastToMe:  true,
			isCastOther: false,
			buff:        buf,
		})
		// e.GetSpace().TravsalCenter(center, radius, func(ia iserver.ICoordEntity) bool {
		// 	if ise, ok := ia.(iserver.IEntityStateGetter); ok {
		// 		if ise.GetEntityState() != iserver.Entity_State_Loop {
		// 			return false
		// 		}
		// 		if !ia.ExistsAOIWeather(e) {
		// 			return false
		// 		}
		// 		if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
		// 			ie.CastMsgToMeRaw(buf)
		// 			// ie.CastMsgToMe(msg)
		// 			// ie.Post(iserver.ServerTypeClient, msg)
		// 		}
		// 	}
		// 	return false
		// })
	} else {
		li := make(map[uint64][]uint64)
		e.GetSpace().TravsalCenter(center, radius, func(ia iserver.ICoordEntity) bool {
			if ise, ok := ia.(iserver.IEntityStateGetter); ok {
				if ise.GetEntityState() != iserver.Entity_State_Loop {
					return false
				}
				if !ia.ExistsAOIWeather(e) {
					return false
				}
				if ie, ok := ia.(iserver.IEntity); ok {
					sid, _, _ := ie.GetEntitySrvID(iserver.ServerTypeClient)
					li[sid] = append(li[sid], ie.GetID())
				}
				// if ie, ok := ia.(iserver.IClientBroadcaster); ok && ia.GetID() != e.GetID() {
				// 	ie.CastMsgToMeRaw(buf)
				// 	// ie.CastMsgToMe(msg)
				// 	// ie.Post(iserver.ServerTypeClient, msg)
				// }
			}
			return false
		})
		// //自己部分
		// sid, _, _ := e.GetEntitySrvID(iserver.ServerTypeClient)
		// li[sid] = append(li[sid], e.GetID())
		for sid, eids := range li {
			e.GetSpace().BroadCastMsgRaw(sid, iserver.ServerTypeClient, 0,
				buf, eids...)
		}
	}
}

// CastRPCToAllClient 触发RPC消息给所有关注我的客户端
func (e *Entity) CastRPCToAllClient(methodName string, args ...interface{}) {
	data := serializer.Serialize(args...)
	msg := &msgdef.RPCMsg{}
	msg.ServerType = iserver.ServerTypeClient
	msg.MethodName = methodName
	msg.Data = data

	e.delayedCastMsgs = append(e.delayedCastMsgs, &delayedCastMsg{
		msg:         msg,
		isCastToMe:  true,
		isCastOther: true,
	})
}

// CastRPCToMe 触发自己的RPC消息
func (e *Entity) CastRPCToMe(methodName string, args ...interface{}) {
	e.RPC(iserver.ServerTypeClient, methodName, args...)
}

// CastRPCToAllClientExceptMe 触发除了自己以外的其它客户端的RPC消息
func (e *Entity) CastRPCToAllClientExceptMe(methodName string, args ...interface{}) {
	data := serializer.Serialize(args...)
	msg := &msgdef.RPCMsg{}
	msg.ServerType = iserver.ServerTypeClient
	msg.MethodName = methodName
	msg.Data = data

	e.delayedCastMsgs = append(e.delayedCastMsgs, &delayedCastMsg{
		msg:         msg,
		isCastToMe:  false,
		isCastOther: true,
	})
}

// PostToClient 投递消息给客户端
func (e *Entity) PostToClient(msg msgdef.IMsg) error {
	return e.Post(iserver.ServerTypeClient, msg)
}

// FlushDelayedCastMsgs 发送所有缓冲的Cast消息
func (e *Entity) FlushDelayedCastMsgs() {
	if len(e.delayedCastMsgs) == 0 {
		return
	}

	for _, dcm := range e.delayedCastMsgs {
		// 填充RPC消息中的SrcEntityID字段
		if rpcMsg, ok := dcm.msg.(*msgdef.RPCMsg); ok {
			rpcMsg.SrcEntityID = e.GetID()
		}
		// if dcm.isCastOther {
		// 	// 这里用自己的AOI列表，因为里面加入了部分额外观察列表（isUpdate2BeWatcher），而且用自己的列表，后面可以做一些优化，
		// 	// 如：限制AOI里的实体数量，把玩家和tinyentity分开管理等
		// 	e.aoiList.Walk(AOI_Watcher, func(en common.Keyer) bool {
		// 		ie := en.(iserver.ICoordEntity)
		// 		if ise, ok := ie.(iserver.IEntityStateGetter); ok {
		// 			if ise.GetEntityState() != iserver.Entity_State_Loop {
		// 				return true
		// 			}

		// 			if ie, ok := ie.(iserver.IEntity); ok {
		// 				ie.Post(iserver.ServerTypeClient, dcm.msg)
		// 			}
		// 		}
		// 		return true
		// 	})
		// 	/*
		// 	   是不是可以考虑不在AOI范围的对象，我的rpc消息他可以不需要知道呢？
		// 	*/
		// 	e.TravsalExtWatchs(func(o *extWatchEntity) {
		// 		// 需要同步给被观察者信息的实体，已经在被观察者的AOI里了，这里不需要同步
		// 		if o.isUpdate2BeWatcher {
		// 			return
		// 		}
		// 		if ise, ok := o.entity.(iserver.IEntityStateGetter); ok {
		// 			if ise.GetEntityState() != iserver.Entity_State_Loop {
		// 				return
		// 			}

		// 			if ie, ok := o.entity.(iserver.IEntity); ok {
		// 				ie.Post(iserver.ServerTypeClient, dcm.msg)
		// 			}
		// 		}
		// 	})
		// }
		if dcm.isCastToMe {
			if dcm.msg != nil {
				e.Post(iserver.ServerTypeClient, dcm.msg)
			} else {
				e.PostRaw(iserver.ServerTypeClient, dcm.buff)
			}
		}
	}

	e.delayedCastMsgs = e.delayedCastMsgs[0:0]
}

// 设置在Loop结束的时候，需要广播发消息的方法（主要用于技能有关的RPC消息）
func (e *Entity) SetLoopedMsg(f func()) {
	e.LoopSendMsgList = append(e.LoopSendMsgList, f)
}
